import {
  getPSUIActionByModelObject,
  IPSAppDataEntity,
  IPSAppDEField,
  IPSAppDEMethod,
  IPSAppView,
  IPSNavigateContext,
  IPSNavigateParam,
} from '@ibiz/dynamic-model-api';
import { IUIDataParam, IUIEnvironmentParam, IUIUtilParam } from '../../interface';
import { LogUtil, ModelTool, UIActionTool, Util } from '../../util';
import { Subject } from 'rxjs';
import { UIActionResult } from '../../logic';
import { AppGlobalUtil } from '../utils';
import { AppDEUIAction } from './app-ui-action';

export class AppBackEndAction extends AppDEUIAction {
  /**
   * 初始化AppBackEndAction
   *
   * @memberof AppBackEndAction
   */
  constructor(opts: any, context?: any) {
    super(opts, context);
  }

  /**
   * 执行界面行为
   *
   * @param UIDataParam 操作数据参数
   * @param UIEnvironmentParam 操作环境参数
   * @param UIUtilParam 操作工具参数
   * @param deUIService 界面UI服务
   * @param context 附加上下文
   * @param params 附加参数
   *
   * @memberof AppBackEndAction
   */
  public async execute(
    UIDataParam: IUIDataParam,
    UIEnvironmentParam: IUIEnvironmentParam,
    UIUtilParam: IUIUtilParam,
    deUIService?: any,
    context: any = {},
    params: any = {},
  ) {
    // 处理参数
    const actionParam = this.beforeExecute(UIDataParam, UIEnvironmentParam, UIUtilParam);
    const { actionContext: actionContext, event: event, xData: xData } = actionParam;
    let { args: args } = actionParam;
    // 执行逻辑
    if (Object.is(this.actionModel?.uILogicAttachMode, 'REPLACE')) {
      return this.executeDEUILogic(UIDataParam, UIEnvironmentParam, UIUtilParam);
    }
    const actionTarget: string | null = this.actionModel.actionTarget;
    if (this.actionModel.enableConfirm && this.actionModel.confirmMsg) {
      const openConfirmBox = async () => {
        return new Promise((resolve: any, reject: any) => {
          const options = {
            title: '警告',
            content: `${this.actionModel.confirmMsg}`,
            buttons: [
              {
                text: '取消',
                handler: () => resolve(false),
              },
              {
                text: '确认',
                handler: () => resolve(true),
              },
            ],
          };
          App.getMsgboxService().open(options);
        });
      };
      if (!(await openConfirmBox())) {
        return;
      }
    }
    if (Object.is(actionTarget, 'MULTIDATA')) {
      LogUtil.warn('多项数据暂未支持');
    } else {
      let data: any = {};
      let tempData: any = {};
      let parentContext: any = {};
      let parentViewParam: any = {};
      const _this: any = actionContext;
      if (this.actionModel.saveTargetFirst && xData) {
        const result: any = await xData.save(args, false);
        if (Object.is(actionTarget, 'SINGLEDATA')) {
          Object.assign(args[0], result.data);
        } else {
          args = [result.data];
        }
      }
      const appDataEntity = this.actionModel.getPSAppDataEntity();
      if (Object.is(actionTarget, 'SINGLEKEY') || Object.is(actionTarget, 'MULTIKEY')) {
        // todo 后台调用获取主键及主信息属性的name
        const entityName = appDataEntity?.codeName.toLowerCase();
        const key = (
          ModelTool.getAppEntityKeyField(appDataEntity) as IPSAppDEField
        )?.name.toLowerCase();
        const majorKey = (
          ModelTool.getAppEntityMajorField(appDataEntity) as IPSAppDEField
        )?.name.toLowerCase();
        if (args[0]?.[key]) {
          Object.assign(context, { [entityName!]: `%${key}%` });
        } else {
          Object.assign(context, { [entityName!]: `%${entityName}%` });
        }
        Object.assign(params, { [key!]: `%${key}%` });
        Object.assign(params, { [majorKey]: `%${majorKey}%` });
      } else if (Object.is(actionTarget, 'SINGLEDATA')) {
        data = args[0];
      }
      // 自定义导航参数优先级大于预置导航参数
      const navigateContexts = this.actionModel.getPSNavigateContexts();
      if (navigateContexts && navigateContexts.length > 0) {
        const localContext = Util.formatNavParam(navigateContexts);
        Object.assign(context, localContext);
      }
      const navgateParams = this.actionModel.getPSNavigateParams();
      if (navgateParams && navgateParams.length > 0) {
        const localParam = Util.formatNavParam(navgateParams);
        Object.assign(params, localParam);
      }
      if (_this.context) {
        parentContext = _this.context;
      }
      if (_this.viewparams) {
        parentViewParam = _this.viewparams;
      }
      context = UIActionTool.handleContextParam(actionTarget, args, parentContext, parentViewParam, context);
      if (Object.is(actionTarget, 'SINGLEDATA')) {
        tempData = UIActionTool.handleActionParam(actionTarget, args, parentContext, parentViewParam, params);
        Object.assign(data, tempData);
      } else {
        data = UIActionTool.handleActionParam(actionTarget, args, parentContext, parentViewParam, params);
      }
      // 多项数据主键转换数据
      if (Object.is(actionTarget, 'MULTIKEY')) {
        const tempDataArray: Array<any> = [];
        if (args.length > 1 && Object.keys(data).length > 0) {
          for (let i = 0; i < args.length; i++) {
            const tempObject: any = {};
            Object.keys(data).forEach((key: string) => {
              Object.assign(tempObject, { [key]: data[key].split(',')[i] });
            });
            tempDataArray.push(tempObject);
          }
        } else {
          tempDataArray.push(data);
        }
        data = tempDataArray;
      }
      context = Object.assign({}, actionContext.context, context);
      // 构建srfparentdename和srfparentkey
      const parentObj: any = {
        srfparentdename: UIEnvironmentParam.parentDeCodeName ? UIEnvironmentParam.parentDeCodeName : null,
        srfparentkey: UIEnvironmentParam.parentDeCodeName
          ? context[UIEnvironmentParam.parentDeCodeName.toLowerCase()]
          : null,
      };
      if (!Object.is(actionTarget, 'MULTIKEY')) {
        Object.assign(data, parentObj);
      }
      Object.assign(context, parentObj);
      if (context && context.srfsessionid) {
        context.srfsessionkey = context.srfsessionid;
        delete context.srfsessionid;
      }
      const backend = () => {
        if (appDataEntity && this.actionModel.getPSAppDEMethod()) {
          App.getEntityService()
            .getService(context, appDataEntity.codeName?.toLowerCase())
            .then(async (curService: any) => {
              // todo 后台调用实体行为类型缺失getPSDEAction.getActionMode 暂时使用多数据做批操作Batch判断
              const method: IPSAppDEMethod = this.actionModel.getPSAppDEMethod() as IPSAppDEMethod;
              const methodCodeName = Object.is(actionTarget, 'MULTIKEY') ? method.codeName + 'Batch' : method?.codeName;
              const viewLoadingService = actionContext.viewLoadingService ? actionContext.viewLoadingService : {};
              viewLoadingService.isLoading = true;
              curService[methodCodeName](context, data, this.actionModel.showBusyIndicator)
                .then(async (response: any) => {
                  if (Object.is(actionTarget, 'SINGLEDATA')) {
                    Util.clearAdditionalData(tempData, args[0]);
                  }
                  if (!response || response.status !== 200) {
                    LogUtil.warn('执行后台界面行为异常');
                    return;
                  }
                  const { data } = response;
                  Object.assign(args[0], data);
                  viewLoadingService.isLoading = false;
                  if (this.actionModel.showBusyIndicator) {
                    if (this.actionModel.successMsg) {
                      LogUtil.log(this.actionModel.successMsg);
                    }
                  }
                  if (this.actionModel.reloadData && xData && xData.refresh && xData.refresh instanceof Function) {
                    xData.refresh(args);
                  }
                  if (this.actionModel.closeEditView) {
                    actionContext.closeView(null);
                  }
                  // 后续界面行为
                  if (this.actionModel.M?.getNextPSUIAction) {
                    const { data: result } = response;
                    let _args: any[] = [];
                    if (Object.is(actionContext.$util.typeOf(result), 'array')) {
                      _args = [...result];
                    } else if (Object.is(actionContext.$util.typeOf(result), 'object')) {
                      _args = [{ ...result }];
                    } else {
                      _args = [...args];
                    }
                    getPSUIActionByModelObject(this.actionModel).then((nextUIaction: any) => {
                      if (nextUIaction) {
                        const [tag, appDeName] = nextUIaction.id.split('@');
                        if (deUIService) {
                          return deUIService.excuteAction(tag, UIDataParam, UIEnvironmentParam, UIUtilParam);
                        }
                      } else {
                        return AppGlobalUtil.executeGlobalAction(
                          nextUIaction.id,
                          UIDataParam,
                          UIEnvironmentParam,
                          UIUtilParam,
                        );
                      }
                    });
                  } else {
                    if (Object.is(this.actionModel?.uILogicAttachMode, 'AFTER')) {
                      return this.executeDEUILogic(UIDataParam, UIEnvironmentParam, UIUtilParam);
                    } else {
                      return new UIActionResult({ ok: true, result: args });
                    }
                  }
                })
                .catch((response: any) => {
                  viewLoadingService.isLoading = false;
                  if (response) {
                    App.getNoticeService().error(response);
                  }
                });
            });
        }
      };
      if (this.actionModel.getFrontPSAppView()) {
        const frontPSAppView: IPSAppView | null = this.actionModel.getFrontPSAppView();
        await frontPSAppView?.fill(true);
        if (!frontPSAppView) {
          return;
        }
        if (frontPSAppView.openMode && frontPSAppView.openMode?.indexOf('DRAWER') !== -1) {
          const container: Subject<any> = App.getOpenViewService().openDrawer(
            { viewModel: frontPSAppView },
            context,
            data,
            UIDataParam.navData,
          );
          container.subscribe((result: any) => {
            if (result && Object.is(result.ret, 'OK')) {
              Object.assign(data, { srfactionparam: result.datas });
              backend();
            }
          });
        } else {
          const container: Subject<any> = App.getOpenViewService().openModal(
            { viewModel: frontPSAppView },
            context,
            data,
            UIDataParam.navData,
          );
          container.subscribe((result: any) => {
            if (result && Object.is(result.ret, 'OK')) {
              Object.assign(data, { srfactionparam: result.datas });
              backend();
            }
          });
        }
      } else {
        backend();
      }
    }
  }
}
